const FS = require('fs');
const PATH = require('path');
const http = require('http');
const URL = require('url');
const https = require('https');
const cheerio = require('cheerio');
const formidable = require('formidable');
const {RequestCode, ResposeCode,GlobalPaths} = require("./basic");
const Log = require("./logger");
const Cacher = require("./module_data_cache");
const ShellCall = require("./shell-call");

function GetAllMetaData(req, res, data) {
    let _package = {};
    _package.data = Cacher.GetSummary();
    _package.code = RequestCode.OK;
    res.json(_package);
}

function AddMetaData(req, res, data) {
    let _package = {};
    _package.code = Cacher.AddMetaData(data.data);
    res.json(_package);
}

function UpdateMetaData(req, res, data) {
    let _package = {};
    _package.code = Cacher.UpdateMetaData(data.data);
    res.json(_package);
}

function DeleteMetaData(req, res, data) {
    let _package = {};
    _package.code = Cacher.DeletePage(data.PID);
    res.json(_package);
}

function GetArticleData(req, res, data) {
    //console.log(`[debug] GetArticleData,data is :\n${String(data)}`);
    let _package = {code: RequestCode.OK, data: Cacher.GetArticleData(data.PID)};
    res.json(_package);
}

function AddSectionData(req, res, data) {
    res.json(Cacher.AddSectionData(data.PID, data.index, data.data));
}

function MoveSectionData(req, res, data) {
    let _package = {};
    Cacher.MoveSectionData(data.PID, data.WID, data.index);
    res.json(_package);
}
function UpdateSectionData(req, res, data) {
    let _package = Cacher.UpdateSectionData(data.PID, data.data);
    res.json(_package);
}

function DeleteSectionData(req, res, data) {
    let _package = {};
    Cacher.DeleteSectionData(data.PID, data.WID);
    res.json(_package);
}

function Archive(req, res, data) {
    ShellCall.GitAdd((v1) => {
        if(v1) {
            ShellCall.GitCommit(`archive at ${new Date().toString()}`, (v2) => {
                if(v2) {
                    //ShellCall.GitPush('origin', 'master', (v3) => {
                        let _package = {code: ResposeCode.OK};
                        res.json(_package);
                        return;
                    //});
                }
            });
        }
    });
    /*
    let _package = {code: ResposeCode.SHELL_CALL_ERROR, msg: "archive failed."};
    res.json(_package);
    */
}

function GetClientStatus(req, res) {
    ShellCall.GitLog((ok, stdout) => {
        if(ok) {
            let _package = {code: ResposeCode.OK, data: stdout};
            res.json(_package);
            return;
        }
    });
}

const _ASSETS_PATH_ = GlobalPaths.ROOT_CLIENT + 'assets/';
function GetFolderContentInfo(req, res, data) {
    let _path = _ASSETS_PATH_;
    if(data && data.path) {
        _path += data.path;
    }
    const _data = {
        'path': data ? data.path : './',
        'folders': [],
        'imgs': [],
        'archives': [],
        'others': [],
    }
    FS.readdirSync(_path).forEach(function (name) {
        const filePath = PATH.join(_path, name);
        const stat = FS.statSync(filePath);
        if(stat.isFile()) {
            if(name.indexOf('jpg') > 0) _data.imgs.push(name);
            else if(name.indexOf('jpeg') > 0) _data.imgs.push(name);
            else if(name.indexOf('bmp') > 0) _data.imgs.push(name);
            else if(name.indexOf('png') > 0) _data.imgs.push(name);
            else if(name.indexOf('svg') > 0) _data.imgs.push(name);
            else if(name.indexOf('zip') > 0) _data.archives.push(name);
            else if(name.indexOf('7z') > 0) _data.archives.push(name);
            else if(name.indexOf('7zip') > 0) _data.archives.push(name);
            else if(name.indexOf('gzip') > 0) _data.archives.push(name);
            else if(name.indexOf('rar') > 0) _data.archives.push(name);
            else if(name.indexOf('tar.gz') > 0) _data.archives.push(name);
            else _data.others.push(name);
        } else if (stat.isDirectory()) {
            _data.folders.push(name);
        }
    });
    const _package = {code: ResposeCode.OK, data: _data};
    res.json(_package);
}

function SaveUploadingData(req, res, data) {
    const form = formidable({
        multiples: true,
        uploadDir: __dirname
    });

    form.parse(req, (err, fields, files) => {
        if(err) {
            const _package = {code: ResposeCode.FAIL, msg: err.toString()};
            res.json(_package);
            return;
        }
        console.log('fields:', fields);
        console.log('files:', files);
        const _package = {code: ResposeCode.OK};
        res.json(_package);
    });
    form.once('error', console.error);
    form.once('end', () => {
        console.log('Done!');
    });


    /*
    form.on('fileBegin', (formname, file) => {
        form.emit('data', {name: 'fileBegin', formname, value: file});
    });

    form.on('file', (formname, file) => {
        form.emit('data', {name: 'file', formname, value: file});
    });

    form.on('field', (fieldName, fieldValue) => {
        form.emit('data', {name: 'field', key: fieldName, value: fieldValue});
    });

    // If you want to customize whatever you want...
    form.on('data', ({name, key, value, buffer, start, end, formname, ...more}) => {
        if(name === 'partBegin') {
        }
        if(name === 'partData') {
        }
        if(name === 'headerField') {
        }
        if(name === 'headerValue') {
        }
        if(name === 'headerEnd') {
        }
        if(name === 'headersEnd') {
        }
        if(name === 'field') {
            console.log('field name:', key);
            console.log('field value:', value);
        }
        if(name === 'file') {
            console.log('file:', formname, value);
        }
        if(name === 'fileBegin') {
            console.log('fileBegin:', formname, value);
        }
    });
    */
}

function UpdateExternalWebInfo(req, res, data) {
    const q = URL.parse(data.url, true);
    let _protocal;
    switch(q.protocol){
        case "http:":
            _protocal = http;
        break;
        case "https:":
            _protocal = https;
        break;
    }
    if(_protocal) {
        ///Log.Info(`requesting url is: ${data.url}`);
        _protocal.get(data.url, function (_sy) {
            let str = '';
            //Log.Info('Response is: ', _sy.statusCode);

            _sy.on('data', function (chunk) {
                //Log.Info(`data stream...`);
                str += chunk;
            });

            _sy.on('end', function () {
                const $ = cheerio.load(str);
                ///Log.Debug(str);
                //const _head = $('head');
                //Log.Info(`head html is: ${_head.toString()}`);
                //<meta property="og:description" content="Documentation for the Tailwind CSS framework.">
                const url = data.url;
                const title = $('title').text();
                let desc = $("meta[name='description']").attr('content');
                desc = desc ?? $("meta[name='og:description']").attr('content');
                desc = desc ?? $("meta[name='twitter:description']").attr('content');
                let imgSrc = $("meta[property='image']").attr('content');
                imgSrc = imgSrc ?? $("meta[property='og:image']").attr('content');
                imgSrc = imgSrc ?? $("meta[property='twitter:image']").attr('content');
                if(imgSrc && !imgSrc.startsWith('http')){
                    imgSrc = url + imgSrc;
                }
                let favIcon = $("link[type='image/png']").attr('href');
                if(favIcon && !favIcon.startsWith('http')){
                    favIcon = url + favIcon;
                }


                const _package = {code: ResposeCode.OK, data: {title, desc, url, favIcon, imgSrc}};
                res.json(_package);
            });
        });
    } else {
        const _package = {code: ResposeCode.OK_WITH_INFO, msg: `can not recognise protocal of ${data.url}`};
        res.json(_package);
    }
}

const _mapHandler = new Map();
_mapHandler.set(RequestCode.GET_FOLDER_CONTENT_INFO, GetFolderContentInfo);
_mapHandler.set(RequestCode.GET_ALL_META_DATA, GetAllMetaData);
_mapHandler.set(RequestCode.ADD_META_DATA, AddMetaData);
_mapHandler.set(RequestCode.UPDATE_META_DATA, UpdateMetaData);
_mapHandler.set(RequestCode.DELETE_META_DATA, DeleteMetaData);
_mapHandler.set(RequestCode.GET_ARTICLE_DATA, GetArticleData);
_mapHandler.set(RequestCode.ADD_SECTION_DATA, AddSectionData);
_mapHandler.set(RequestCode.UPDATE_SECTION_DATA, UpdateSectionData);
_mapHandler.set(RequestCode.MOVE_SECTION_DATA, MoveSectionData);
_mapHandler.set(RequestCode.DELETE_SECTION_DATA, DeleteSectionData);
_mapHandler.set(RequestCode.UPDATE_EXTERNAL_WEB_INNFO, UpdateExternalWebInfo);
_mapHandler.set(RequestCode.ARCHIVE, Archive);
_mapHandler.set(RequestCode.CLIENT_STATUS, GetClientStatus);
_mapHandler.set(RequestCode.UPLOAD_FILES, SaveUploadingData);

module.exports.Serve = (req, res) => {
    let _package = req.body;
    let _fn = _mapHandler.get(_package.code);
    //console.log("code:", _package.code);
    if(_fn) {
        _fn(req, res, _package.data);
    } else {
        Log.Error('no such requesting code: ', _package.code);
        res.end(JSON.stringify({code: ResposeCode.OK, msg: "error requesting code."}));
    }
}

